﻿using System;
using System.Data;
using System.Data.OracleClient;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Text;

namespace xfsale.lib
{
    public static class App
    {
        private static SortedList<string, SysMenu> _menuSet = new SortedList<string, SysMenu>(StringComparer.OrdinalIgnoreCase);
        private static SortedList<string, SysDict> _dictSet = new SortedList<string, SysDict>(StringComparer.OrdinalIgnoreCase);
        private static SortedList<string, SysProc> _procSet = new SortedList<string, SysProc>(StringComparer.OrdinalIgnoreCase);
        private static SysOp _op = new SysOp();
        private static SysInfo _sys = new SysInfo();
        private static OracleConnection _conn = new OracleConnection();

        public static SortedList<string, SysMenu> MenuSet
        {
            get { return _menuSet; }
        }

        public static SortedList<string, SysDict> DictSet
        {
            get { return _dictSet; }
        }

        public static SortedList<string, SysProc> ProcSet
        {
            get { return _procSet; }
        }

        public static SysOp Op
        {
            get { return _op; }
        }

        public static SysInfo Sys
        {
            get { return _sys; }
        }

        public static OracleConnection Conn
        {
            get { return _conn; }
        }

        public static SysProc GetProc(string procName)
        {
            if (string.IsNullOrEmpty(procName))
                return null;

            if (_procSet.ContainsKey(procName))
            {
                return _procSet[procName];
            }

            procName = procName.ToUpper();
            SysProc proc = new SysProc();

            IDbCommand command = _conn.CreateCommand();
            command.CommandText = @"select object_id, object_name from user_objects ";
            command.CommandText += "where object_name = :procName ";
            command.CommandText += "and object_type = 'PROCEDURE'";
            command.Parameters.Clear();
            command.Parameters.Add(new OracleParameter("procName", procName));
            IDataReader reader = command.ExecuteReader();
            if (!reader.Read())
            {
                Log.ThrowError("存储过程不存在. procName={0}", procName);
            }

            int objectId = Convert.ToInt32(reader["object_id"]);
            proc.Name = Convert.ToString(reader["object_name"]);

            command.CommandText = @"select argument_name, data_type, nvl(data_length, 0) data_length, in_out, position
                from user_arguments
                where object_id = :objectId
                order by argument_name asc";
            command.Parameters.Clear();
            command.Parameters.Add(new OracleParameter("objectId", objectId));
            reader = command.ExecuteReader();
            while (reader.Read())
            {
                SysProcParam param = new SysProcParam();
                param.Name = Convert.ToString(reader["argument_name"]);
                param.Type = Convert.ToString(reader["data_type"]);
                param.Length = Convert.ToInt32(reader["data_length"]);
                param.Direction = Convert.ToString(reader["in_out"]);
                param.Position = Convert.ToInt32(reader["position"]);
                proc.Params.Add(param.Name, param);
            }
            reader.Close();

            _procSet.Add(procName, proc);

            return proc;
        }


        public static void CallProc(SysProc proc)
        {
            try
            {
                Log.Debug("开始调用：");
                Log.Debug("\t{0}", proc.Name);
                OracleCommand command = _conn.CreateCommand();
                command.CommandType = CommandType.StoredProcedure;
                command.CommandText = proc.Name;
                command.Parameters.Clear();

                foreach (SysProcParam param in proc.Params.Values)
                {
                    if (param.Direction == "OUT")
                    {
                        if (param.Type == "VARCHAR" || param.Type == "VARCHAR2")
                        {
                            if (param.Length <= 0)
                            {
                                Log.ThrowError("未指定可变输出参数长度 paramName={0}", param.Name);
                            }
                        }
                    }
                }

                List<SysProcParam> paramList = new List<SysProcParam>();
                foreach (SysProcParam p in proc.Params.Values)
                {
                    paramList.Add(p);
                }
                paramList.Sort(new Comparison<SysProcParam>(CompareProcParam));
                foreach (SysProcParam p in paramList)
                {
                    OracleParameter param = new OracleParameter();
                    param.ParameterName = p.Name;
                    switch (p.Direction.ToUpper())
                    {
                        case "IN":
                            param.Direction = ParameterDirection.Input;
                            param.Value = (p.Value == null) ? string.Empty : p.Value;
                            break;
                        case "OUT":
                            param.Direction = ParameterDirection.Output;
                            param.Size = p.Length;
                            break;
                    }
                    command.Parameters.Add(param);
                }
                paramList.Clear();
                paramList = null;

                Log.Debug("输入参数:");
                foreach (OracleParameter p in command.Parameters)
                {
                    switch (p.Direction)
                    {
                        case ParameterDirection.Input:
                            Log.Debug("\t{0}={1}", p.ParameterName, p.Value);
                            break;
                    }
                }

                command.ExecuteNonQuery();

                Log.Debug("输出参数:");
                foreach (OracleParameter p in command.Parameters)
                {
                    switch (p.Direction)
                    {
                        case ParameterDirection.Output:
                            proc.Params[p.ParameterName].Value = Convert.ToString(p.Value);
                            Log.Debug("\t{0}={1}", p.ParameterName, p.Value);
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                Log.ThrowError("调用过程出错procName={0}. {1}", proc.Name, ex.Message);
            }
        }

        public static void Init()
        {
            //初始化日志
            _InitLog();

            Log.Debug("开始初始化客户端");

            //初始化数据库连接
            Log.Debug("开始初始化数据库连接");
            _InitDB();

            //开始初始化菜单信息
            Log.Debug("初始化菜单信息");
            _InitMenu();

            //开始初始化字典信息
            Log.Debug("初始化字典信息");
            _InitDict();

            //开始初始化操作员
            Log.Debug("初始化操作员信息");
            _InitGlobal();

            Log.Debug("结束初始化客户端");
        }

        public static void Dispose()
        {
            Log.Debug("开始释放客户端");

            //开始释放操作员
            Log.Debug("释放操作员信息");
            _DisposeGlobal();

            //开始释放字典信息
            Log.Debug("释放字典信息");
            _DisposeDict();

            //开始释放菜单信息
            Log.Debug("释放菜单信息");
            _DisposeMenu();

            //开始释放数据库连接
            Log.Debug("释放数据库连接");
            _DisposeDB();

            Log.Debug("结束释放客户端");
        }

        private static void _InitLog()
        {
            try
            {
                Log.LogTo = Convert.ToInt32(ConfigurationSettings.AppSettings["LogTo"]);
                Log.LogLevel = Convert.ToInt32(ConfigurationSettings.AppSettings["LogLevel"]);
                Log.LogFile = ConfigurationSettings.AppSettings["LogFile"];
                Log.LogReset = ConfigurationSettings.AppSettings["LogReset"].ToUpper().Equals("Y");
            }
            catch
            {
                Log.LogTo = Log.LOGTO_FILE;
                Log.LogLevel = Log.LOGLVL_DEBUG;
                Log.LogFile = "Runtime.log";

                Log.ThrowError("读取日志配置失败");
            }

            try
            {
                if (Log.LogReset)
                {
                    File.Delete(Log.LogFile);
                }
            }
            catch
            {
                Log.ThrowError("删除日志文件失败");
            }

        }

        private static void _DisposeLog()
        {
            Log.LogTo = Log.LOGTO_FILE;
            Log.LogLevel = Log.LOGLVL_DEBUG;
            Log.LogFile = "Runtime.log";
        }

        private static void _InitDB()
        {
            try
            {
                _conn.ConnectionString = ConfigurationManager.ConnectionStrings["Oracle"].ConnectionString;
                _conn.Open();
            }
            catch
            {
                Log.ThrowError("初始化数据库连接失败");
                _DisposeDB();
            }
        }

        private static void _DisposeDB()
        {
            if (_conn != null)
            {
                _conn.Close();
                _conn.Dispose();
            }
        }

        private static void _InitMenu()
        {
            IDbCommand command = Conn.CreateCommand();
            command.CommandText = @"select * from SysMenu where menuEnabled=1 order by MenuID asc";
            IDataReader reader = command.ExecuteReader();
            while (reader.Read())
            {
                SysMenu mi = new SysMenu();
                mi.Id = Convert.ToString(reader["MenuID"]);
                mi.Caption = Convert.ToString(reader["MenuCaption"]);
                mi.Icon = Convert.ToString(reader["MenuIcon"]);
                //mi.Order = Convert.ToInt32(reader["MenuOrder"]);
                mi.Enabled = Convert.ToBoolean(Convert.ToInt32(reader["MenuEnabled"]));
                mi.ServiceCode = Convert.ToString(reader["ServiceCode"]);
                mi.UIDll = Convert.ToString(reader["UIDll"]);
                mi.UIFrame = Convert.ToString(reader["UIFrame"]);
                mi.CallService = Convert.ToString(reader["CallService"]);
                mi.CallMethod = Convert.ToString(reader["CallMethod"]);
                mi.CallProc = Convert.ToString(reader["CallProc"]);
                mi.Summary = Convert.ToString(reader["Summary"]);
                _menuSet.Add(mi.Id, mi);
            }
            reader.Close();
        }

        private static void _DisposeMenu()
        {
            if (_menuSet != null)
            {
                _menuSet.Clear();
            }
        }

        private static void _InitDict()
        {
            IDbCommand command = Conn.CreateCommand();
            command.CommandText = @"select * from XmDict order by ItemName asc";
            IDataReader reader = command.ExecuteReader();
            while (reader.Read())
            {
                SysDict di = new SysDict();
                di.Name = Convert.ToString(reader["ItemName"]);
                di.Type = Convert.ToString(reader["ItemType"]);
                di.Precise = Convert.ToInt32(reader["ItemPrecise"]);
                di.Scale = Convert.ToInt32(reader["ItemScale"]);
                di.Desc = Convert.ToString(reader["ItemDesc"]);
                di.Verify = Convert.ToString(reader["ItemVerify"]);
                di.Default = Convert.ToString(reader["ItemDefault"]);
                _dictSet.Add(di.Name, di);
            }
            reader.Close();

            command.CommandText = @"select * from XmDictValue order by ItemName asc, ItemValue asc";
            reader = command.ExecuteReader();
            while (reader.Read())
            {
                string itemName = Convert.ToString(reader["ItemName"]);
                if (_dictSet.ContainsKey(itemName))
                {
                    SysDictValue dv = new SysDictValue();
                    dv.Value = Convert.ToString(reader["ItemValue"]);
                    dv.Desc = Convert.ToString(reader["ValueDesc"]);
                    //dv.Order = Convert.ToInt32(reader["ValueOrder"]);

                    _dictSet[itemName].Values.Add(dv);
                }
            }
            reader.Close();
        }

        private static void _DisposeDict()
        {
            if (_dictSet != null)
            {
                _dictSet.Clear();
            }
        }

        private static void _InitGlobal()
        {
        }

        private static void _DisposeGlobal()
        {
        }

        private static int CompareProcParam(SysProcParam x, SysProcParam y)
        {
            return x.Position - y.Position;
        }
    }
}
